﻿using RockBus.Transport.Interfaces;
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading.Tasks;

namespace RockBus.ServiceBus
{
    [ServiceBehavior(
        ConcurrencyMode = ConcurrencyMode.Multiple,
        InstanceContextMode = InstanceContextMode.Single)]
    public class SubscriberService : IOneWay, ITwoWay
    {
        public SubscriberService(IMessageHandler messageHandler)
        {
            this.MessageHandler = messageHandler;
        }

        private IMessageHandler MessageHandler { get; set; }

        #region IOneWay

        IAsyncResult IOneWay.BeginProcessMessage(Message message, AsyncCallback callback, object state)
        {
            return this.MessageHandler.ProcessMessageAsync(message, null)
            .ToAsync(callback, state);
        }

        void IOneWay.EndProcessMessage(IAsyncResult asyncResult)
        {
            Task task = asyncResult as Task;
            if ((null == task) || (null != task.Exception))
            {
                Exception exc = new Exception(string.Format("Delivery Failure on message with action {0}", OperationContext.Current.IncomingMessageHeaders.Action), (null == task) ? null : task.Exception);
                throw exc;
            }
        }

        #endregion IOneWay

        #region ITwoWay

        IAsyncResult ITwoWay.BeginProcessRequest(Message message, AsyncCallback callback, object state)
        {
            return this.MessageHandler.ProcessRequestAsync(message, null)
            .ToAsync(callback, state);
        }

        Message ITwoWay.EndProcessRequest(IAsyncResult asyncResult)
        {
            Task<Message> task = asyncResult as Task<Message>;
            if ((null == task) || (null != task.Exception))
            {
                Exception exc = new Exception(string.Format("Delivery Failure on message with action {0}", OperationContext.Current.IncomingMessageHeaders.Action), (null == task) ? null : task.Exception);
                throw exc;
            }

            return task.Result;
        }

        #endregion ITwoWay
    }
}